package core.router;

import core.CommandLine;
import core.schedulers.DataKind;
import eduni.simanim.Anim_port;
import eduni.simjava.Sim_entity;
import eduni.simjava.Sim_event;
import eduni.simjava.Sim_port;
import eduni.simjava.Sim_system;

public class Router extends Sim_entity {

	private Sim_port in, out;
	private double delay;
	private double bandwidth;
	private int qtdPacotes;
	private DataKind kind;
	// tamanho medio fila
	private double tamanhoMedioFila;
	private int contadorMedicaoFila;
	private double tamanhoPacote;
	private double utilizacaoMedia;

	private int aMedir = 100;
	private int medidos;
	private double somaMedidos;

	private double tamanhoTotal;
	private double pacotesContados;

	private CommandLine panel;
	private int contadorMedioUtilizacao;

	public Router(String name, int x, int y, String image, double bandwidth,
			DataKind kind, CommandLine panel, double tam) {

		super(name, image, x, y);

		tamanhoPacote = tam;

		if (kind.equals(DataKind.LAN)) {
			in = new Sim_port("In1", "port", Anim_port.LEFT, 20);
			out = new Sim_port("Out1", "port", Anim_port.RIGHT, 20);
		} else {
			in = new Sim_port("In2", "port", Anim_port.RIGHT, 60);
			out = new Sim_port("Out2", "port", Anim_port.LEFT, 60);
		}

		add_port(in);
		add_port(out);

		this.kind = kind;

		delay = 0;

		this.tamanhoMedioFila = 0;
		this.contadorMedicaoFila = 0;

		this.bandwidth = bandwidth;
		qtdPacotes = 0;

		this.panel = panel;

		this.contadorMedioUtilizacao = 0;

	}

	public void body() {

		double tempoEsperaPacotes = 0;
		double tempoSimulacao = 0;
		int counter = 0;
		double tempoTotal = 0;
		double tempoMedioOciso = 0;
		int contadorPacotes = 0;
		double comecou = Sim_system.sim_clock();
		double ant = 0;
		double atu = 0;

		while (Sim_system.running()) {

			tempoSimulacao = Sim_system.sim_clock() - counter;

			Sim_event e = new Sim_event();
			sim_get_next(e);
			Packet pacote = (Packet) e.get_data();
			if (pacote == null)
				continue;

			tempoMedioOciso += Sim_system.sim_clock() - comecou;

			pacote.setLeftTime(Sim_system.sim_clock());

			double queueTime = pacote.getQueueTime();

			if (medidos < aMedir) {
				medidos++;
				somaMedidos += queueTime;
				atu += queueTime;
				if (medidos == aMedir) {
					System.out
							.println("AGORA EM " + kind + " = " + (atu / 100));
					medidos = 0;
					atu = 0;
					ant++;
				}
			}

			delay = pacote.getSize() / bandwidth;

			sim_process(delay);
			sim_completed(e);

			if (tempoSimulacao >= 1.0) {
				utilizacaoMedia += (tamanhoPacote / bandwidth)
						* contadorPacotes;
				contadorMedioUtilizacao++;
				contadorPacotes = 0;
				tempoEsperaPacotes = 0;
				qtdPacotes = 0;
				tempoSimulacao = 0;
				counter++;
				tempoTotal += tempoMedioOciso / Sim_system.sim_clock();
				System.out.println("OCIOSO AGORA EM " + kind + " = " + (tempoMedioOciso / Sim_system.sim_clock()));
			}
			qtdPacotes++;
			tempoEsperaPacotes += pacote.getQueueTime();

			if (kind.equals(DataKind.LAN)) {
				sim_schedule(out, delay, 1);
				sim_trace(1, "S Out1");
			} else {
				sim_schedule(out, delay, 1);
				sim_trace(1, "S Out2");
			}
			comecou = Sim_system.sim_clock();
			contadorPacotes++;
		}
		
		System.out.println("TEMPO MEDIO OCIOSO EM " + kind + " : "
				+ (tempoTotal/counter));

		System.out.println("TEMPO MEDIO ESPERA " + kind + ": "
				+ (somaMedidos / (100 * ant)));

		utilizacaoMedia = utilizacaoMedia / contadorMedioUtilizacao;
		tamanhoMedioFila = tamanhoMedioFila / contadorMedicaoFila;

		if (Double.isNaN(utilizacaoMedia)) {
			utilizacaoMedia = 0.0;
		}

		if (kind.equals(DataKind.LAN)) {
			panel.setUtilizacaoMediaLanValue(utilizacaoMedia);
			panel.setTamanhoMedioDaFilaLanValue(tamanhoMedioFila);
		} else {
			panel.setUtilizacaoMediaNetValue(utilizacaoMedia);
			panel.setTamanhoMedioDaFilaNetValue(tamanhoMedioFila);
		}

	}

	public void setBandwidth(double bandwidth) {
		this.bandwidth = bandwidth;
	}

	public double getBandwidth() {
		return bandwidth;
	}

	public double getTamanhoMedioFila() {
		return tamanhoMedioFila;
	}

	public void setTamanhoMedioFila(double tamanhoMedioFila) {
		this.tamanhoMedioFila = tamanhoMedioFila;
	}

	public int getContadorMedicaoFila() {
		return contadorMedicaoFila;
	}

	public void setContadorMedicaoFila(int contadorMedicaoFila) {
		this.contadorMedicaoFila = contadorMedicaoFila;
	}

	public void contarPacote() {
		tamanhoTotal += sim_waiting();
		pacotesContados++;
		if (pacotesContados == aMedir) {
			tamanhoMedioFila += tamanhoTotal / aMedir;
			tamanhoTotal = 0;
			contadorMedicaoFila++;
		}
	}
}